package com.backend.service.user.impl;

import ch.qos.logback.core.util.MD5Util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.MD5;
import com.backend.mapper.user.UserMapper;
import com.backend.service.email.EmailService;
import com.backend.service.user.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.constant.EmailContentConstant;
import com.common.constant.MessageConstant;
import com.common.constant.RedisConstant;
import com.common.exception.EmailException;
import com.common.exception.LoginException;
import com.common.exception.RegisterException;
import com.common.result.Result;
import com.common.threadlocal.UserLocal;
import com.pojo.dto.LoginDTO;
import com.pojo.dto.RegisterDTO;
import com.pojo.dto.UserDTO;
import com.pojo.entity.User;
import com.pojo.vo.UserVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final UserMapper userMapper;
    private final EmailService emailService;
    private final StringRedisTemplate stringRedisTemplate;
    @Override
    public String login(LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        User user = userMapper.getUserByUsername(username);
        if (user == null) {
            throw new LoginException(MessageConstant.USER_NOT_EXISTS);
        }
        String passwordByChanged = DigestUtils.md5DigestAsHex(password.getBytes());
        log.info("password:{}", passwordByChanged);
        if (!passwordByChanged.equals(user.getPassword())) {
            throw new LoginException(MessageConstant.PASSWORD_ERROR);
        }
        if (user.getStatus() != 0) {
            throw new LoginException(MessageConstant.USER_NOT_USE);
        }
        String userId = user.getId().toString();
        String token = RedisConstant.LOGIN_USER_KEY + userId;
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(), CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? "" : fieldValue.toString()));
        //这里不需要再设置useLocal，只要在每一次请求执行的时候获取，请求结束释放就行了
        stringRedisTemplate.opsForHash().putAll(token, userMap);
        stringRedisTemplate.expire(token, RedisConstant.LOGIN_USER_TTL, TimeUnit.MINUTES);
        log.info("用户已登录");
        return userId;
    }

    @Override
    public UserDTO me() {
        UserDTO userDTO = UserLocal.getCurrentUserDTO();
        log.info("userDTO:{}", userDTO);
        return userDTO;
    }

    @Override
    public void logout() {
        String token = RedisConstant.LOGIN_USER_KEY + UserLocal.getCurrentUserDTO().getId().toString();
        Boolean delete = stringRedisTemplate.delete(token);
        if (delete) {
            return ;
        }
        throw new RuntimeException("删除错误");
    }

    @Override
    public void register(RegisterDTO registerDTO) {
        String yzmKey = RedisConstant.REGISTER_YZM + registerDTO.getUsername();
        String yzm = stringRedisTemplate.opsForValue().get(yzmKey);
        if (StrUtil.isBlank(yzm)) {
            throw new RegisterException(MessageConstant.NOT_HAS_YZM);
        }
        if (!yzm.equals(registerDTO.getYzm())) {
            throw new RegisterException(MessageConstant.YZM_ERROR);
        }
        User user = BeanUtil.copyProperties(registerDTO, User.class);
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        user.setCreateDatetime(LocalDateTime.now());
        user.setUpdateDatetime(LocalDateTime.now());
        save(user);
    }

    @Override
    public void sendMail(RegisterDTO registerDTO) {
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(RedisConstant.REGISTER_YZM + registerDTO.getUsername()))) {
            throw new EmailException(MessageConstant.HAS_EXISTS_YZM);
        }
        String yzm = RandomUtil.randomNumbers(6);
        String title = EmailContentConstant.REGISTER_YZM_TITLE;
        String content = EmailContentConstant.REGISTER_YZM_CONTENT + yzm;
        boolean flag = emailService.send(registerDTO.getEmail(), title, content);
        if (!flag) {
            throw new EmailException(MessageConstant.SEND_MESSAGE_ERROR);
        }
        stringRedisTemplate.opsForValue().set(RedisConstant.REGISTER_YZM + registerDTO.getUsername(), yzm, RedisConstant.REGISTER_YZM_TTL, TimeUnit.SECONDS);
    }
}
